package org.yunai.swjg.server.module.item.operation.use;

import com.alibaba.fastjson.JSON;
import org.slf4j.Logger;
import org.springframework.stereotype.Component;
import org.yunai.swjg.server.core.constants.SysMessageConstants;
import org.yunai.swjg.server.entity.ItemEntity;
import org.yunai.swjg.server.module.currency.Currency;
import org.yunai.swjg.server.module.currency.CurrencyService;
import org.yunai.swjg.server.module.item.Inventory;
import org.yunai.swjg.server.module.item.ItemDef;
import org.yunai.swjg.server.module.item.container.Bag;
import org.yunai.swjg.server.module.item.container.EquipmentBag;
import org.yunai.swjg.server.module.item.container.ShoulderBag;
import org.yunai.swjg.server.module.item.template.EquipmentItemTemplate;
import org.yunai.swjg.server.module.item.template.ItemTemplate;
import org.yunai.swjg.server.module.item.template.MaterialItemTemplate;
import org.yunai.swjg.server.module.item.template.ReelItemTemplate;
import org.yunai.swjg.server.module.item.vo.Item;
import org.yunai.swjg.server.module.player.vo.Player;
import org.yunai.swjg.server.rpc.message.S_C.S_C_ItemUseReelResp;
import org.yunai.swjg.server.rpc.message.S_C.S_C_SysMessageReq;
import org.yunai.yfserver.common.LoggerFactory;
import org.yunai.yfserver.spring.BeanManager;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * 装备合成卷轴使用操作
 * User: yunai
 * Date: 13-6-2
 * Time: 下午2:15
 */
@Component
public class UseEquipmentReelOperation extends AbstractItemUseOperation {

    private static final Logger LOGGER = LoggerFactory.getLogger(LoggerFactory.Logger.item, UseEquipmentReelOperation.class);

    private static CurrencyService currencyService;

    static {
        currencyService = BeanManager.getBean(CurrencyService.class);
    }

    @Override
    public boolean isSuitable(Player player, Item item, int equipmentId) {
        return item.getBagType() == Bag.BagType.PRIM
                && item.getTemplate().getType() == ItemDef.Type.EQUIP_REEL;
    }

    /**
     * 判断合成材料是否足够。合成材料来源有主背包/仓库背包。
     *
     * @param player       玩家信息
     * @param item         道具
     * @param equipmentId  装备道具编号。当为0时，从主背包/仓库查找。
     * @param useGoldParam 是否使用元宝参数
     * @return 材料是否足够
     */
    @Override
    protected boolean canUseImpl(Player player, Item item, int equipmentId, int useGoldParam) {
        ReelItemTemplate template = (ReelItemTemplate) item.getTemplate();
        boolean result = true;
        boolean useGold = (useGoldParam == 1);
        int needGold = 0; // 需要元宝
        // 第一步，检查有没合成需要的装备
        Object[] needEquipmentObjs = getEquipment(player, item, equipmentId);
        int needEquipmentTemplateId = (int) needEquipmentObjs[0];
        Item needEquipment = (Item) needEquipmentObjs[1];
        if (needEquipment == null) {
            if (equipmentId != 0) { // 当有选择好的目标武器材料，结果该材料还找不到，即使玩家选择了使用元宝，也认为不能合成
                result = false;
            } else if (useGold) { // 当使用钱时，但是钱不够买武器的时候，则将needEquipment设置为null，便于下面统一判断
                needGold += ItemTemplate.getItemTemplate(needEquipmentTemplateId, EquipmentItemTemplate.class).getGold();
                if (!currencyService.canCost(player, Currency.GOLD, needGold, false)) {
                    result = false;
                }
            } else {
                result = false;
            }
        }
        // 第二步，继续判断材料是否足够
        if (result) {
            ShoulderBag primBag = player.getInventory().getPrimBag();
            ShoulderBag deportBag = player.getInventory().getDeportBag();
            for (Map.Entry<Integer, Integer> needItem : template.getNeedItems().entrySet()) {
                if (needItem.getKey() == needEquipmentTemplateId) { // 需要的装备不进行判断
                    continue;
                }
                int ownCount = primBag.getCountByTemplateId(needItem.getKey()); // 主背包
                if (ownCount >= needItem.getValue()) {
                    continue;
                }
                ownCount += deportBag.getCountByTemplateId(needItem.getKey()); // 主背包 + 仓库
                if (ownCount >= needItem.getValue()) {
                    continue;
                }
                if (!useGold) { // 道具不够，又不花钱
                    result = false;
                    break;
                }
                needGold += ItemTemplate.getItemTemplate(needItem.getKey(), MaterialItemTemplate.class).getGold() * (needItem.getValue() - ownCount);
                if (!currencyService.canCost(player, Currency.GOLD, needGold, false)) { // 道具不够，花的钱又不够
                    result = false;
                    break;
                }
            }
        }
        // 最后，发送结果消息
        if (!result) {
            player.message(new S_C_SysMessageReq(SysMessageConstants.ITEM_NOT_ENOUGH));
            player.message(new S_C_ItemUseReelResp((byte) 0));
            return false;
        }
        return true;
    }

    /**
     * 合成装备。合成后，装备等级需要降低5.
     *
     * @param player       玩家信息
     * @param item         道具
     * @param equipmentId  装备道具编号。当为0时，从主背包/仓库查找。
     * @param useGoldParam 是否使用元宝参数
     * @return 使用结果
     */
    @Override
    protected boolean useImpl(Player player, Item item, int equipmentId, int useGoldParam) {
        ReelItemTemplate template = (ReelItemTemplate) item.getTemplate();
        List<Item> updateItems = new ArrayList<>();
        int needGold = 0;
        // 第一步，寻找装备材料，并扣掉装备
        Object[] needEquipmentObjs = getEquipment(player, item, equipmentId);
        int needEquipmentTemplateId = (int) needEquipmentObjs[0];
        Item needEquipment = (Item) needEquipmentObjs[1];
        if (needEquipment == null) {
            needGold += ItemTemplate.getItemTemplate(needEquipmentTemplateId, EquipmentItemTemplate.class).getGold();
        } else {
            needEquipment.changeOverlap(0);
        }
        // 第二步，扣除材料道具
        Inventory inventory = player.getInventory();
        ShoulderBag primBag = inventory.getPrimBag();
        ShoulderBag deportBag = inventory.getDeportBag();
        for (Map.Entry<Integer, Integer> needItem : template.getNeedItems().entrySet()) {
            if (needItem.getKey() == needEquipmentTemplateId) { // 需要的装备不进行判断
                continue;
            }
            int count = needItem.getValue();
            count = consumeItem(primBag, needItem.getKey(), count, updateItems);
            if (count > 0) {
                count = consumeItem(deportBag, needItem.getKey(), count, updateItems);
            }
            if (count > 0) {
                needGold += ItemTemplate.getItemTemplate(needItem.getKey(), MaterialItemTemplate.class).getGold() * count;
            }
        }
        // 第三步，扣除元宝
        if (needGold > 0) {
            currencyService.cost(player, Currency.GOLD, needGold);
        }
        // 第四步，扣除装备合成卷轴
        item.changeOverlap(0);
        updateItems.add(item);
        // 第五步，给新装备到主背包。若原装备材料有携带者，将装备装备到携带者身上。另外，原装备若存在，需要进行降级
        List<Item> addEquipments = primBag.addItem(template.getGainTemplate(), template.getGainCount());
        if (addEquipments.size() != 1) {
            List<ItemEntity> addEquipmentEntities = new ArrayList<>(addEquipments.size());
            for (Item addEquipment : addEquipments) {
                addEquipmentEntities.add(addEquipment.toEntity());
            }
            LOGGER.error("[useImpl] [player({}) use equipment reel({}) get equipment({})]", player.getId(), template.getId(), JSON.toJSONString(addEquipmentEntities));
        }
        Item getEquipment = addEquipments.get(0);
        updateItems.add(getEquipment);
        if (needEquipment != null) { // 原装备有携带者，装备到携带者身上。
            // TODO 少考虑了武器等级
            if (needEquipment.getWearId() != Item.OWNER_ID_NONE) {
                getEquipment.changeOwner(needEquipment.getWearId());
                EquipmentBag equipmentBag = (EquipmentBag) inventory.getBag(getEquipment.getWearId(), Bag.BagType.EQUIPMENT);
                primBag.move(getEquipment, equipmentBag, EquipmentBag.getPosition(getEquipment.getType()));
                player.getRole(getEquipment.getWearId()).calcRoleProps(true);
            }
        }
        // 发消息
        inventory.sendModifyMessage(updateItems); // 发送背包变化
        player.message(new S_C_ItemUseReelResp((byte) 1)); // 发送合成结果
        return true;
    }

    /**
     * 获得装备道具模版编号和装备道具
     *
     * @param player      玩家信息
     * @param item        合成装备卷轴道具
     * @param equipmentId 装备道具编号。当为0时，从主背包/仓库查找。
     * @return [装备道具模版编号, 装备道具]
     */
    private Object[] getEquipment(Player player, Item item, int equipmentId) {
        ReelItemTemplate template = (ReelItemTemplate) item.getTemplate();
        int needEquipmentTemplateId = template.getNeedItems().keySet().iterator().next(); // 合成需要的装备编号
        Item needEquipment;
        if (equipmentId == 0) { // 先从主背包查找，在从仓库查找
            needEquipment = player.getInventory().getPrimBag().getFirstByTemplateId(needEquipmentTemplateId);
            if (needEquipment == null) {
                needEquipment = player.getInventory().getDeportBag().getFirstByTemplateId(needEquipmentTemplateId);
            }
        } else {
            needEquipment = player.getInventory().getItemById(equipmentId);
            if (needEquipment != null && needEquipment.getTemplateId() != needEquipmentTemplateId) { // 当道具存在，但是该道具不是该合成需求时，认为不存在该道具
                needEquipment = null;
            }
            if (needEquipment != null) {
                switch (needEquipment.getBagType()) { // 合成的装备材料只能在主背包/仓库背包/装备背包。
                    case PRIM:
                    case DEPOT:
                    case EQUIPMENT:
                        break;
                    default:
                        needEquipment = null;
                }
            }
        }
        return new Object[]{needEquipmentTemplateId, needEquipment};
    }
}